﻿using System;
using System.Collections;
using System.Text;

namespace startup.Common.Json
{
    public abstract class JsonValue : IEnumerable
    {
        /// <summary>
        ///     汉字是否采用UNICODE编码输出
        /// </summary>
        protected bool UnescapedUnicode;

        #region 公开属性

        internal abstract object Value { get; }

        /// <summary>
        ///     对象类型
        /// </summary>
        public abstract JsonType JsonType { get; }

        /// <summary>
        ///     索引器
        /// </summary>
        /// <param name="key">通过键开访问，JsonArray不支持该索引器</param>
        /// <returns></returns>
        public virtual JsonValue this[string key]
        {
            get { throw new InvalidOperationException("Unsupported on this JsonValue"); }
            set { throw new InvalidOperationException("Unsupported on this JsonValue"); }
        }

        public virtual JsonValue this[int index]
        {
            get { throw new InvalidOperationException("UnsupportedOnThisJsonValue"); }
            set { throw new InvalidOperationException("UnsupportedOnThisJsonValue"); }
        }

        public virtual int Count
        {
            get { throw new InvalidOperationException("Unsupported on this JsonValue"); }
        }

        #endregion

        #region 构造函数

        internal JsonValue()
        {
            UnescapedUnicode = false;
        }

        #endregion

        IEnumerator IEnumerable.GetEnumerator()
        {
            throw new InvalidOperationException("Unsupported on this JsonValue");
        }

        /// <summary>
        ///     在StringBuilder中构建该对象的Json格式字符串输出
        /// </summary>
        /// <param name="stream">操作的StringBuilder对象</param>
        internal abstract void Builder(StringBuilder stream);

        /// <summary>
        ///     将JSON字符串转换成Json对象
        /// </summary>
        /// <param name="jsonString"></param>
        /// <returns></returns>
        public static JsonValue Parse(string jsonString)
        {
            if (jsonString == null)
            {
                throw new ArgumentNullException("jsonString");
            }

            if (jsonString.Length == 0)
            {
                throw new ArgumentException("Json String cannot be empty");
            }

            //解析JSON字符串
            var parser = new JsonReader(jsonString);
            return parser.Parser();
        }

        public static bool TryParse(string jsonString, out JsonValue value)
        {
            if (String.IsNullOrWhiteSpace(jsonString))
            {
                value = null;
                return false;
            }
            //解析JSON字符串
            var parser = new JsonReader(jsonString);
            bool success = parser.TryParser(out value);
            return success;
        }

        /// <summary>
        ///     将对象转成JsonValue对象
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        internal static JsonValue Convert(object value)
        {
            if (value == null)
            {
                return null;
            }
            //对象
            var dictionary = value as IDictionary;
            if (dictionary != null)
            {
                return new JsonObject(dictionary);
            }
            //数组
            var list = value as IList;
            if (list != null)
            {
                return new JsonArray(list);
            }
            //元数据
            return new JsonPrimitive(value);
        }

        /// <summary>
        ///     检测对象是否为空，为空则抛出异常
        /// </summary>
        /// <param name="obj">待检查对象</param>
        /// <param name="parameterName">异常消息</param>
        internal static void CheckNull(object obj, string parameterName)
        {
            if (obj == null)
            {
                throw new ArgumentNullException(parameterName);
            }
        }

        /// <summary>
        ///     检测对象是否为空，为空则抛出异常
        /// </summary>
        /// <param name="valueType">JsonValue的JsonType</param>
        /// <param name="targetType">匹配的JsonType</param>
        private static void CheckIfJsonType(JsonType valueType, JsonType targetType)
        {
            if (valueType != targetType)
            {
                throw new InvalidCastException("cannot cast JsonValue");
            }
        }

        public string Stringify(bool isUnescapedUnicode = false)
        {
            UnescapedUnicode = isUnescapedUnicode;
            var result = new StringBuilder();
            Builder(result);
            return result.ToString();
        }

        public virtual bool ContainsKey(string key)
        {
            throw new InvalidOperationException("Unsupported on this JsonValue");
        }

        public static bool operator ==(JsonValue lhs, object rhs)
        {
            if (ReferenceEquals(lhs, null))
            {
                return ReferenceEquals(rhs, null);
            }
            return lhs.Equals(rhs);
        }

        public static bool operator !=(JsonValue lhs, object rhs)
        {
            if (ReferenceEquals(lhs, null))
            {
                return !ReferenceEquals(rhs, null);
            }
            return !lhs.Equals(rhs);
        }

        public override bool Equals(object obj)
        {
            return Value.Equals(obj);
        }

        public override int GetHashCode()
        {
            return Value.GetHashCode();
        }

        #region 基基类隐式转换成 Json 元类型(JsonPrimitive)

        public static implicit operator string(JsonValue value)
        {
            if (value == null)
            {
                return null;
            }
            CheckIfJsonType(value.JsonType, JsonType.String);
            return (string)value.Value;
        }

        public static implicit operator double(JsonValue value)
        {
            CheckIfJsonType(value.JsonType, JsonType.Number);
            return System.Convert.ToDouble(value.Value);
        }

        public static implicit operator float(JsonValue value)
        {
            CheckIfJsonType(value.JsonType, JsonType.Number);
            return System.Convert.ToSingle(value.Value);
        }

        public static implicit operator decimal(JsonValue value)
        {
            CheckIfJsonType(value.JsonType, JsonType.Number);
            return System.Convert.ToDecimal(value.Value);
        }

        public static implicit operator long(JsonValue value)
        {
            CheckIfJsonType(value.JsonType, JsonType.Number);
            return System.Convert.ToInt64(value.Value);
        }

        public static implicit operator ulong(JsonValue value)
        {
            CheckIfJsonType(value.JsonType, JsonType.Number);
            return System.Convert.ToUInt64(value.Value);
        }

        public static implicit operator int(JsonValue value)
        {
            CheckIfJsonType(value.JsonType, JsonType.Number);
            return System.Convert.ToInt32(value.Value);
        }

        public static implicit operator uint(JsonValue value)
        {
            CheckIfJsonType(value.JsonType, JsonType.Number);
            return System.Convert.ToUInt32(value.Value);
        }

        public static implicit operator short(JsonValue value)
        {
            CheckIfJsonType(value.JsonType, JsonType.Number);
            return System.Convert.ToInt16(value.Value);
        }

        public static implicit operator ushort(JsonValue value)
        {
            CheckIfJsonType(value.JsonType, JsonType.Number);
            return System.Convert.ToUInt16(value.Value);
        }

        public static implicit operator sbyte(JsonValue value)
        {
            CheckIfJsonType(value.JsonType, JsonType.Number);
            return System.Convert.ToSByte(value.Value);
        }

        public static implicit operator byte(JsonValue value)
        {
            CheckIfJsonType(value.JsonType, JsonType.Number);
            return System.Convert.ToByte(value.Value);
        }

        public static implicit operator DateTime(JsonValue value)
        {
            CheckIfJsonType(value.JsonType, JsonType.String);
            return DateTime.Parse(value);
        }

        public static implicit operator char(JsonValue value)
        {
            CheckIfJsonType(value.JsonType, JsonType.String);
            if (value.Value is char)
            {
                return (char)value.Value;
            }

            char[] array = ((string)value.Value).ToCharArray();
            if (array.Length != 1)
            {
                throw new InvalidCastException("cannot cast string to char");
            }

            return array[0];
        }

        public static implicit operator bool(JsonValue value)
        {
            CheckIfJsonType(value.JsonType, JsonType.Boolean);
            return (bool)value.Value;
        }

        #endregion

        #region 基基类隐式转换成 Json 元类型(JsonPrimitive)

        public static implicit operator JsonValue(bool value)
        {
            return new JsonPrimitive(value);
        }

        public static implicit operator JsonValue(byte value)
        {
            return new JsonPrimitive(value);
        }

        public static implicit operator JsonValue(decimal value)
        {
            return new JsonPrimitive(value);
        }

        public static implicit operator JsonValue(double value)
        {
            return new JsonPrimitive(value);
        }

        public static implicit operator JsonValue(short value)
        {
            return new JsonPrimitive(value);
        }

        public static implicit operator JsonValue(int value)
        {
            return new JsonPrimitive(value);
        }

        public static implicit operator JsonValue(long value)
        {
            return new JsonPrimitive(value);
        }

        public static implicit operator JsonValue(float value)
        {
            return new JsonPrimitive(value);
        }

        public static implicit operator JsonValue(string value)
        {
            if (value != null)
            {
                return new JsonPrimitive(value);
            }
            return null;
        }

        public static implicit operator JsonValue(char value)
        {
            return new JsonPrimitive(value);
        }

        public static implicit operator JsonValue(DateTime value)
        {
            return new JsonPrimitive(value);
        }

        public static implicit operator JsonValue(sbyte value)
        {
            return new JsonPrimitive(value);
        }

        public static implicit operator JsonValue(ushort value)
        {
            return new JsonPrimitive(value);
        }

        public static implicit operator JsonValue(uint value)
        {
            return new JsonPrimitive(value);
        }

        public static implicit operator JsonValue(ulong value)
        {
            return new JsonPrimitive(value);
        }

        #endregion
    }
}
